package com.von.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.von.entity.UserRole;
import com.von.enums.ErrorEnum;
import com.von.exceptions.BusinessRuntimeException;
import com.von.mapper.UserMapper;
import com.von.entity.User;
import com.von.service.IRoleService;
import com.von.service.IUserRoleService;
import com.von.service.IUserService;
import com.von.utils.RedisUtils;
import com.von.utils.TokenUtils;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.von.vo.RoleVo;
import com.von.vo.UserPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author pengzhaofeng
 * @since 2020-05-18
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private IRoleService iRoleService;

    @Value(value = "${token.expired.time}")
    private long tokenExpiredTime;

    @Autowired
    private IUserRoleService iUserRoleService;

    @Autowired
    private HttpServletRequest httpServletRequest;

    @Override
    public R<Map> login(User user) {
        User one = lambdaQuery().eq(User::getAccount, user.getAccount()).one();
        if (one == null) {
            return R.failed("该账不存在");
        }
        if (!one.getPassword().equals(user.getPassword())) {
            return R.failed("密码错误");
        }
        Set<String> list = redisUtils.getList("TK-" + one.getId());
        //失效旧token
        list.forEach(a ->
                redisUtils.delete(a)
        );
        String tokenStr = TokenUtils.createToken(String.valueOf(one.getId()));
        one.setPassword(null);
        Map<Object, Object> map = MapUtil.builder().put("role", iRoleService.getByUserId(one.getId())).put("user", one).build();
        redisUtils.set(tokenStr, JSONUtil.toJsonStr(map), tokenExpiredTime);
        map.put("token", tokenStr);
        return R.ok(map);
    }

    @Override
    public R<Map> byToken() {
        String token = httpServletRequest.getHeader("token");
        String s = redisUtils.get(token);
        if (StrUtil.isBlank(s)) {
            throw new BusinessRuntimeException(ErrorEnum.TOKEN_ERROR);
        }
        return R.ok(JSONUtil.parseObj(s));
    }

    @Override
    public R<String> insert(User user) {
        User one = lambdaQuery().eq(User::getAccount, user.getAccount()).one();
        if (one != null) {
            return R.failed("账号已存在");
        }
        save(user);
        return R.ok(null);
    }

    @Override
    public R<String> update(User user) {
        updateById(user);
        User one = getById(user.getId());
        //刷新缓存
        Set<String> list = redisUtils.getList("TK-" + user.getId());
        list.forEach(a -> {
            Map<Object, Object> map = MapUtil.builder().put("role", iRoleService.getByUserId(one.getId())).put("user", one).build();
            redisUtils.set(a, JSONUtil.toJsonStr(map), tokenExpiredTime);
        });
        return R.ok(null);
    }

    @Override
    public R<String> updateRole(RoleVo roleVo) {
        iUserRoleService.lambdaUpdate().eq(UserRole::getUserId, roleVo.getId()).remove();
        roleVo.getIds().forEach(id ->
                iUserRoleService.save(UserRole.builder().userId(roleVo.getId()).roleId(id).build())
        );
        //刷新缓存
        User one = getById(roleVo.getId());
        Set<String> list = redisUtils.getList("TK-" + one.getId());
        list.forEach(a -> {
            Map<Object, Object> map = MapUtil.builder().put("role", iRoleService.getByUserId(one.getId())).put("user", one).build();
            redisUtils.set(a, JSONUtil.toJsonStr(map), tokenExpiredTime);
        });
        return R.ok(null);
    }

    @Override
    public R<String> delete(Map<String, Integer> id) {
        removeById(id.get("id"));
        Set<String> list = redisUtils.getList("TK-" + id.get("id"));
        list.forEach(a -> redisUtils.delete(a));
        return R.ok(null);
    }

    @Override
    public R<String> deleteById(Integer id) {
        removeById(id);
        return R.ok(null);
    }

    @Override
    public R<Page<User>> list(UserPage userPage) {
        LambdaQueryChainWrapper<User> wrapper = lambdaQuery();
        if(StrUtil.isNotBlank(userPage.getName())){
            wrapper.like(User::getName,userPage.getName());
        }
        if(StrUtil.isNotBlank(userPage.getAccount())){
            wrapper.like(User::getAccount,userPage.getAccount());
        }
        if(StrUtil.isNotBlank(userPage.getPhone())){
            wrapper.like(User::getPhone,userPage.getPhone());
        }
        wrapper.orderByDesc(User::getId);
        Page<User> page = wrapper.page(new Page<>(userPage.getPageNum(), userPage.getPageSize()));
        return R.ok(page);
    }

    @Override
    public R<Map> getUser(int id) {
        User byId = getById(id);
        byId.setPassword(null);
        return R.ok(JSONUtil.parseObj(byId).set("role", iRoleService.getByUserId(byId.getId())));
    }
}
